<?php
class Pageley_Gateway_Database_StandardQuerySqlDecoratorTests extends Pageley_Test_Case {
	private $articleType;
	private $keywordType;
	private $categoryType;
	private $table;

	public function setUp() {
		$string = new Pageley_Domain_Attribute_Basic("string");
		$number = new Pageley_Domain_Attribute_Basic("number");
        $namespace = new Pageley_Domain_BasicNamespace("urn:gateway.pageley.org:unit-tests", "mysql", "Pageley_Commerce");
		$this->categoryType = new Pageley_Domain_BasicType(
			$namespace,
			"Category"
		);
        $this->keywordType = new Pageley_Domain_BasicType(
			$namespace,
			"Keyword"
		);
        $category = new Pageley_Domain_Attribute_Reference("category", $this->categoryType);
        $this->categoryType->setAttributes(
			new Pageley_Util_ArrayMap(array(
				"name" => $string,
                "parentCategory" => $category
			)));
        $keywords = new Pageley_Domain_Attribute_OneToManyDecorator(
            new Pageley_Domain_Attribute_Reference("keyword", $this->keywordType));
		$this->articleType = new Pageley_Domain_BasicType(
			$namespace,
			"Article",
			new Pageley_Util_ArrayMap(array(
				"name" => $string,
				"price" => $number,
                "category" => $category,
                "keywords" => $keywords
			))
		);
		$article = new Pageley_Domain_Attribute_Reference("article", $this->articleType);
		$this->keywordType->setAttributes(
			new Pageley_Util_ArrayMap(array(
				"name" => $string,
				"article" => $article
			)));
		$gateway = new Pageley_Gateway_Database(null);
		$this->table = new Pageley_Gateway_Database_BasicTable($this->articleType, $gateway);
	}

	private function newQuery($type, $condition = null, $order = null, $range = null) {
		return new Pageley_Gateway_Database_StandardQuerySqlDecorator(
			new Pageley_Query_Basic($type, $condition, $order, $range), $this->table);
	}

	public function testEmptyCondition() {
		$query = $this->newQuery($this->articleType);
		$this->assertEquals("SELECT a1.\"article_id\", a1.\"name\", a1.\"price\", a1.\"category_id\" "
			. "FROM \"pageley_commerce\".\"article\" AS a1", $query->toSql());
	}

	public function testSingleCondition() {
		$query = $this->newQuery($this->articleType, new Pageley_Query_Condition_Equals("price", 2.5));
		$this->assertEquals("SELECT a1.\"article_id\", a1.\"name\", a1.\"price\", a1.\"category_id\" "
			. "FROM \"pageley_commerce\".\"article\" AS a1 "
			. "WHERE a1.\"price\" = :price1", $query->toSql());
		$this->assertEquals(2.5, $query->getValues()->get("price1"));
	}

	public function testCount() {
		$query = $this->newQuery($this->articleType, new Pageley_Query_Condition_Equals("price", 2.5));
		$this->assertEquals("SELECT COUNT(a1.\"article_id\") AS \"count\" "
			. "FROM \"pageley_commerce\".\"article\" AS a1 "
			. "WHERE a1.\"price\" = :price1", $query->toSql(Pageley_Gateway_Database_QueryType::$COUNT));
		$this->assertEquals(2.5, $query->getValues()->get("price1"));
	}

    public function testAggregateCondition() {
        $category = $this->categoryType->newInstance();
        $category->setId(1);
        $query = $this->newQuery($this->articleType, new Pageley_Query_Condition_AndGroup(
            new Pageley_Util_ArrayMap(
                new Pageley_Query_Condition_GreaterThan("price", 2.5),
                new Pageley_Query_Condition_LessThan("price", 5.0),
                new Pageley_Query_Condition_Equals("category", $category)
            )));
		$this->assertEquals("SELECT a1.\"article_id\", a1.\"name\", a1.\"price\", a1.\"category_id\" "
			. "FROM \"pageley_commerce\".\"article\" AS a1 "
			. "WHERE ( a1.\"price\" > :price1 "
			. "AND a1.\"price\" < :price2 "
            . "AND a1.\"category_id\" = :category1 )", $query->toSql());
		$this->assertEquals(2.5, $query->getValues()->get("price1"));
		$this->assertEquals(5.0, $query->getValues()->get("price2"));
		$this->assertEquals(1, $query->getValues()->get("category1"));
    }

    public function testNotCondition() {
		$query = $this->newQuery($this->articleType, new Pageley_Query_Condition_Not(
            new Pageley_Query_Condition_Equals("price", 2.5)));
		$this->assertEquals("SELECT a1.\"article_id\", a1.\"name\", a1.\"price\", a1.\"category_id\" "
			. "FROM \"pageley_commerce\".\"article\" AS a1 "
			. "WHERE NOT a1.\"price\" = :price1", $query->toSql());
		$this->assertEquals(2.5, $query->getValues()->get("price1"));
    }
    
    public function testOrder() {
        $query = $this->newQuery($this->articleType, null, new Pageley_Util_ArrayMap(array(
                "price" => Pageley_Query_Direction::$DESCENDING,
                "name" => Pageley_Query_Direction::$ASCENDING
            )));
        $this->assertEquals("SELECT a1.\"article_id\", a1.\"name\", a1.\"price\", a1.\"category_id\" "
            . "FROM \"pageley_commerce\".\"article\" AS a1 "
            . "ORDER BY a1.\"price\" DESC, a1.\"name\" ASC", $query->toSql());
    }
    
    public function testRange() {
        $query = $this->newQuery($this->articleType, null, null, new Pageley_Query_Range(6, 10));
        $this->assertEquals("SELECT a1.\"article_id\", a1.\"name\", a1.\"price\", a1.\"category_id\" "
            . "FROM \"pageley_commerce\".\"article\" AS a1 "
            . "OFFSET 5 ROWS FETCH FIRST 5 ROWS ONLY", $query->toSql());
    }
}